home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / pine / imap-3.0 / ANSI / c-client / mtest.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-06-19  |  16.6 KB  |  618 lines

  1. /*
  2.  * Program:    Mail library test program
  3.  *
  4.  * Author:    Mark Crispin
  5.  *        Networks and Distributed Computing
  6.  *        Computing & Communications
  7.  *        University of Washington
  8.  *        Administration Building, AG-44
  9.  *        Seattle, WA  98195
  10.  *        Internet: MRC@CAC.Washington.EDU
  11.  *
  12.  * Date:    8 July 1988
  13.  * Last Edited:    19 June 1993
  14.  *
  15.  * Sponsorship:    The original version of this work was developed in the
  16.  *        Symbolic Systems Resources Group of the Knowledge Systems
  17.  *        Laboratory at Stanford University in 1987-88, and was funded
  18.  *        by the Biomedical Research Technology Program of the National
  19.  *        Institutes of Health under grant number RR-00785.
  20.  *
  21.  * Original version Copyright 1988 by The Leland Stanford Junior University.
  22.  * Copyright 1993 by the University of Washington.
  23.  *
  24.  *  Permission to use, copy, modify, and distribute this software and its
  25.  * documentation for any purpose and without fee is hereby granted, provided
  26.  * that the above copyright notices appear in all copies and that both the
  27.  * above copyright notices and this permission notice appear in supporting
  28.  * documentation, and that the name of the University of Washington or The
  29.  * Leland Stanford Junior University not be used in advertising or publicity
  30.  * pertaining to distribution of the software without specific, written prior
  31.  * permission.  This software is made available "as is", and
  32.  * THE UNIVERSITY OF WASHINGTON AND THE LELAND STANFORD JUNIOR UNIVERSITY
  33.  * DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD TO THIS SOFTWARE,
  34.  * INCLUDING WITHOUT LIMITATION ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
  35.  * FITNESS FOR A PARTICULAR PURPOSE, AND IN NO EVENT SHALL THE UNIVERSITY OF
  36.  * WASHINGTON OR THE LELAND STANFORD JUNIOR UNIVERSITY BE LIABLE FOR ANY
  37.  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
  38.  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
  39.  * CONTRACT, TORT (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF
  40.  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  41.  *
  42.  */
  43.  
  44. #include <stdio.h>
  45. #include <ctype.h>
  46. #include <signal.h>
  47. #include "mail.h"
  48. #include "osdep.h"
  49. #if unix
  50. #include <pwd.h>
  51. #include <netdb.h>
  52. #endif
  53. #ifdef noErr
  54. #include <MacTCPCommonTypes.h>
  55. #include <AddressXlation.h>
  56. #endif
  57. #include "rfc822.h"
  58. #include "smtp.h"
  59. #include "nntp.h"
  60. #include "misc.h"
  61.  
  62.  
  63. char *curhst = NIL;        /* currently connected host */
  64. char *curusr = NIL;        /* current login user */
  65. char personalname[256];        /* user's personal name */
  66. extern DRIVER imapdriver,bezerkdriver,tenexdriver,mboxdriver,mhdriver,
  67.  newsdriver,nntpdriver,dummydriver,dawzdriver;
  68.  
  69. static char *hostlist[] = {    /* SMTP server host list */
  70.   "mailhost",
  71.   "localhost",
  72.   NIL
  73. };
  74.  
  75. static char *newslist[] = {    /* Netnews server host list */
  76.   "news",
  77.   NIL
  78. };
  79.  
  80. void main ();
  81. void mm (MAILSTREAM *stream,long debug);
  82. void header (MAILSTREAM *stream,long msgno);
  83. void display_body (BODY *body,char *pfx,long i);
  84. void status (MAILSTREAM *stream);
  85. void prompt (char *msg,char *txt);
  86. void smtptest (long debug);
  87.  
  88. /* Main program - initialization */
  89.  
  90. void main ()
  91. {
  92.   MAILSTREAM *stream = NIL;
  93.   char tmp[MAILTMPLEN];
  94.   long debug;
  95. #ifdef noErr
  96.   size_t *base = (size_t *) 0x000908;
  97.                 /* increase stack size on a Mac */
  98.   SetApplLimit ((Ptr) (*base - (size_t) 65535L));
  99. #endif
  100. #if unix
  101.   char *name;
  102.   char *suffix;
  103.   struct passwd *pwd;
  104.   struct hostent *host_name;
  105.   gethostname (tmp,MAILTMPLEN);    /* get local name */
  106.                 /* get it in full form */
  107.   curhst = (host_name = gethostbyname (tmp)) ?
  108.     cpystr (host_name->h_name) : cpystr (tmp);
  109.                 /* get user name and passwd entry */
  110.   if (name = (char *) getlogin ()) pwd = getpwnam (name);
  111.   else {
  112.     pwd = getpwuid (getuid ());    /* get it this way if detached, etc */
  113.     name = pwd->pw_name;
  114.   }
  115.   curusr = cpystr (name);    /* current user is this name */
  116.   strcpy (tmp,pwd->pw_gecos);    /* probably not necessay but be safe */
  117.                 /* dyke out the office and phone poop */
  118.   if (suffix = strchr (tmp,',')) suffix[0] = '\0';
  119.   strcpy (personalname,tmp);    /* make a permanent copy of it */
  120. #else
  121.   prompt ("Personal name: ",personalname);
  122.   curusr = cpystr ("somebody");
  123.   curhst = cpystr ("someplace");
  124. #endif
  125.   puts ("MTest -- C client test program");
  126.   mail_link (&imapdriver);    /* link in IMAP driver */
  127. #ifdef MSDOS
  128.   mail_link (&dawzdriver);    /* link in dawz mail driver */
  129.   mail_link (&nntpdriver);    /* link in NNTP driver */
  130.   mail_link (&dummydriver);    /* finally dummy driver at the end */
  131. #endif
  132. #if unix
  133.   mail_link (&tenexdriver);    /* link in Tenex mail driver */
  134.   mail_link (&mhdriver);    /* link in mh mail driver */
  135.   mail_link (&mboxdriver);    /* link in mbox mail driver */
  136.   mail_link (&bezerkdriver);    /* link in Berkeley mail driver */
  137.   mail_link (&newsdriver);    /* link in netnews mail driver */
  138.   mail_link (&nntpdriver);    /* link in NNTP driver */
  139.   mail_link (&dummydriver);    /* finally dummy driver at the end */
  140. #endif
  141.                 /* user wants protocol telemetry? */
  142.   prompt ("Debug protocol (y/n)?",tmp);
  143.   ucase (tmp);
  144.   debug = (tmp[0] == 'Y') ? T : NIL;
  145.   do {
  146.     prompt ("Mailbox ('?' for help): ",tmp);
  147.     if (!strcmp (tmp,"?")) {
  148.       puts ("Enter INBOX, mailbox name, or IMAP mailbox as {host}mailbox");
  149.       puts ("Known local mailboxes:");
  150.       mail_find (NIL,"*");
  151.       puts ("or just hit return to quit");
  152.     }
  153.     else if (tmp[0]) stream = mail_open (stream,tmp,debug ? OP_DEBUG : NIL);
  154.   } while (!stream && tmp[0]);
  155.   mm (stream,debug);        /* run user interface if opened */
  156. #ifdef noErr
  157.                 /* clean up resolver */
  158.   if (resolveropen) CloseResolver ();
  159. #endif
  160. }
  161.  
  162. /* MM command loop
  163.  * Accepts: MAIL stream
  164.  */
  165.  
  166. void mm (MAILSTREAM *stream,long debug)
  167. {
  168.   char cmd[256],cmdx[128];
  169.   char *arg;
  170.   long i;
  171.   long last = 0;
  172.   BODY *body;
  173.   status (stream);        /* first report message status */
  174.   while (stream) {
  175.     prompt ("MTest>",cmd);    /* prompt user, get command */
  176.                 /* get argument */
  177.     if (arg = strchr (cmd,' ')) *arg++ = '\0';
  178.     switch (*ucase (cmd)) {    /* dispatch based on command */
  179.     case 'B':            /* Body command */
  180.       if (arg) last = atoi (arg);
  181.       else if (last == 0 ) {
  182.     puts ("?Missing message number");
  183.     break;
  184.       }
  185.       if (last > 0 && last <= stream->nmsgs) {
  186.     mail_fetchstructure (stream,last,&body);
  187.     if (body) display_body (body,NIL,(long) 0);
  188.     else puts ("%No body information available");
  189.       }
  190.       else puts ("?Bad message number");
  191.       break;
  192.     case 'C':            /* Check command */
  193.       mail_check (stream);
  194.       status (stream);
  195.       break;
  196.     case 'D':            /* Delete command */
  197.       if (arg) last = atoi (arg);
  198.       else {
  199.     if (last == 0) {
  200.       puts ("?Missing message number");
  201.       break;
  202.     }
  203.     arg = cmd;
  204.     sprintf (arg,"%ld",last);
  205.       }
  206.       if (last > 0 && last <= stream->nmsgs)
  207.     mail_setflag (stream,arg,"\\DELETED");
  208.       else puts ("?Bad message number");
  209.       break;
  210.     case 'E':            /* Expunge command */
  211.       mail_expunge (stream);
  212.       last = 0;
  213.       break;
  214.     case 'F':            /* Find command */
  215.       if (!arg) arg = "*";
  216.       puts ("Subscribed mailboxes:");
  217.       mail_find (NIL,arg);
  218.       puts ("Subscribed bboards:");
  219.       mail_find_bboards (NIL,arg);
  220.       puts ("Known mailboxes:");
  221.       mail_find_all (NIL,arg);
  222.       puts ("Known bboards:");
  223.       mail_find_all_bboard (NIL,arg);
  224.       if ((*stream->mailbox == '{') ||
  225.       ((*stream->mailbox == '*') && (stream->mailbox[1] == '{'))) {
  226.     puts ("Remote Subscribed mailboxes:");
  227.     mail_find (stream,arg);
  228.     puts ("Remote Subscribed bboards:");
  229.     mail_find_bboards (stream,arg);
  230.     puts ("Remote known mailboxes:");
  231.     mail_find_all (stream,arg);
  232.     puts ("Remote known bboards:");
  233.     mail_find_all_bboard (stream,arg);
  234.       }
  235.       break;
  236.     case 'G':
  237.       mail_gc (stream,GC_ENV|GC_TEXTS|GC_ELT);
  238.       break;
  239.     case 'H':            /* Headers command */
  240.       if (arg) {
  241.     if (!(last = atoi (arg))) {
  242.       mail_search (stream,arg);
  243.       for (i = 1; i <= stream->nmsgs; ++i)
  244.         if (mail_elt (stream,i)->searched) header (stream,i);
  245.       break;
  246.     }
  247.       }
  248.       else if (last == 0) {
  249.     puts ("?Missing message number");
  250.     break;
  251.       }
  252.       if (last > 0 && last <= stream->nmsgs) header (stream,last);
  253.       else puts ("?Bad message number");
  254.       break;
  255.     case 'M':
  256.       prompt ("Destination: ",cmdx);
  257.       mail_move (stream,arg,cmdx);
  258.       break;
  259.     case 'N':            /* New mailbox command */
  260.       if (!arg) {
  261.     puts ("?Missing mailbox");
  262.     break;
  263.       }
  264.                 /* get the new mailbox */
  265.       while (!(stream = mail_open (stream,arg,debug)))
  266.     prompt ("Mailbox: ",arg);
  267.       last = 0;
  268.       status (stream);
  269.       break;
  270.     case 'Q':            /* Quit command */
  271.       mail_close (stream);
  272.       stream = NIL;
  273.       break;
  274.     case 'S':            /* Send command */
  275.       smtptest (debug);
  276.       break;
  277.     case 'T':            /* Type command */
  278.       if (arg) last = atoi (arg);
  279.       else if (last == 0 ) {
  280.     puts ("?Missing message number");
  281.     break;
  282.       }
  283.       if (last > 0 && last <= stream->nmsgs) {
  284.     printf ("%s",mail_fetchheader (stream,last));
  285.     puts (mail_fetchtext (stream,last));
  286.       }
  287.       else puts ("?Bad message number");
  288.       break;
  289.     case 'U':            /* Undelete command */
  290.       if (arg) last = atoi (arg);
  291.       else {
  292.     if (last == 0 ) {
  293.       puts ("?Missing message number");
  294.       break;
  295.     }
  296.     arg = cmd;
  297.     sprintf (arg,"%ld",last);
  298.       }
  299.       if (last > 0 && last <= stream->nmsgs)
  300.     mail_clearflag (stream,arg,"\\DELETED");
  301.       else puts ("?Bad message number");
  302.       break;
  303.     case 'X':            /* Xit command */
  304.       mail_expunge (stream);
  305.       mail_close (stream);
  306.       stream = NIL;
  307.       break;
  308.     case '+':
  309.       mail_debug (stream); debug = T;
  310.       break;
  311.     case '-':
  312.       mail_nodebug (stream); debug = NIL;
  313.       break;
  314.     case '?':            /* ? command */
  315.       puts ("Body, Check, Delete, Expunge, Find, GC, Headers, Move,");
  316.       puts (" New Mailbox, Quit, Send, Type, Undelete, Xit,");
  317.       puts (" +, -, or <RETURN> for next message");
  318.       break;
  319.     case '\0':        /* null command (type next message) */
  320.       if (last > 0 && last++ < stream->nmsgs) {
  321.     printf ("%s",mail_fetchheader (stream,last));
  322.     puts (mail_fetchtext (stream,last));
  323.       }
  324.       else puts ("%No next message");
  325.       break;
  326.     default:            /* bogus command */
  327.       printf ("?Unrecognized command: %s\n",cmd);
  328.       break;
  329.     }
  330.   }
  331. }
  332.  
  333. /* MM display header
  334.  * Accepts: IMAP2 stream
  335.  *        message number
  336.  */
  337.  
  338. void header (MAILSTREAM *stream,long msgno)
  339. {
  340.   unsigned long i;
  341.   char tmp[256];
  342.   char *t;
  343.   MESSAGECACHE *cache = mail_elt (stream,msgno);
  344.   mail_fetchstructure (stream,msgno,NIL);
  345.   tmp[0] = cache->recent ? (cache->seen ? 'R': 'N') : ' ';
  346.   tmp[1] = (cache->recent | cache->seen) ? ' ' : 'U';
  347.   tmp[2] = cache->flagged ? 'F' : ' ';
  348.   tmp[3] = cache->answered ? 'A' : ' ';
  349.   tmp[4] = cache->deleted ? 'D' : ' ';
  350.   sprintf (tmp+5,"%4ld) ",cache->msgno);
  351.   mail_date (tmp+11,cache);
  352.   tmp[17] = ' ';
  353.   tmp[18] = '\0';
  354.   mail_fetchfrom (tmp+18,stream,msgno,(long) 20);
  355.   strcat (tmp," ");
  356.   if (i = cache->user_flags) {
  357.     strcat (tmp,"{");
  358.     while (i) {
  359.       strcat (tmp,stream->user_flags[find_rightmost_bit (&i)]);
  360.       if (i) strcat (tmp," ");
  361.     }
  362.     strcat (tmp,"} ");
  363.   }
  364.   mail_fetchsubject (t = tmp + strlen (tmp),stream,msgno,(long) 25);
  365.   sprintf (t += strlen (t)," (%ld chars)",cache->rfc822_size);
  366.   puts (tmp);
  367. }
  368.  
  369. /* MM display body
  370.  * Accepts: BODY structure pointer
  371.  *        prefix string
  372.  *        index
  373.  */
  374.  
  375. void display_body (BODY *body,char *pfx,long i)
  376. {
  377.   char tmp[256];
  378.   char *s = tmp;
  379.   PARAMETER *par;
  380.   PART *part;            /* multipart doesn't have a row to itself */
  381.   if (body->type == TYPEMULTIPART) {
  382.                 /* if not first time, extend prefix */
  383.     if (pfx) sprintf (tmp,"%s%ld.",pfx,++i);
  384.     else tmp[0] = '\0';
  385.     for (i = 0,part = body->contents.part; part; part = part->next)
  386.       display_body (&part->body,tmp,i++);
  387.   }
  388.   else {            /* non-multipart, output oneline descriptor */
  389.     if (!pfx) pfx = "";        /* dummy prefix if top level */
  390.     sprintf (s," %s%ld %s",pfx,++i,body_types[body->type]);
  391.     if (body->subtype) sprintf (s += strlen (s),"/%s",body->subtype);
  392.     if (body->description) sprintf (s += strlen (s)," (%s)",body->description);
  393.     if (par = body->parameter) do
  394.       sprintf (s += strlen (s),";%s=%s",par->attribute,par->value);
  395.     while (par = par->next);
  396.     if (body->id) sprintf (s += strlen (s),", id = %s",body->id);
  397.     switch (body->type) {    /* bytes or lines depending upon body type */
  398.     case TYPEMESSAGE:        /* encapsulated message */
  399.     case TYPETEXT:        /* plain text */
  400.       sprintf (s += strlen (s)," (%ld lines)",body->size.lines);
  401.       break;
  402.     default:
  403.       sprintf (s += strlen (s)," (%ld bytes)",body->size.bytes);
  404.       break;
  405.     }
  406.     puts (tmp);            /* output this line */
  407.                 /* encapsulated message? */
  408.     if (body->type == TYPEMESSAGE && (body = body->contents.msg.body)) {
  409.       if (body->type == TYPEMULTIPART) display_body (body,pfx,i-1);
  410.       else {            /* build encapsulation prefix */
  411.     sprintf (tmp,"%s%ld.",pfx,i);
  412.     display_body (body,tmp,(long) 0);
  413.       }
  414.     }
  415.   }
  416. }
  417.  
  418. /* MM status report
  419.  * Accepts: MAIL stream
  420.  */
  421.  
  422. void status (MAILSTREAM *stream)
  423. {
  424.   long i;
  425.   char date[50];
  426.   rfc822_date (date);
  427.   puts (date);
  428.   if (stream) {
  429.     if (stream->mailbox) printf ("Mailbox: %s, %ld messages, %ld recent\n",
  430.                  stream->mailbox,stream->nmsgs,stream->recent);
  431.     else puts ("%No mailbox is open on this stream");
  432.     if (stream->user_flags[0]) {
  433.       printf ("Keywords: %s",stream->user_flags[0]);
  434.       for (i = 1; i < NUSERFLAGS && stream->user_flags[i]; ++i)
  435.     printf (", %s",stream->user_flags[i]);
  436.       puts ("");
  437.     }
  438.   }
  439. }
  440.  
  441.  
  442. /* Prompt user for input
  443.  * Accepts: pointer to prompt message
  444.  *          pointer to input buffer
  445.  */
  446.  
  447. void prompt (char *msg,char *txt)
  448. {
  449.   printf ("%s",msg);
  450.   gets (txt);
  451. }
  452.  
  453. /* Interfaces to C-client */
  454.  
  455.  
  456. void mm_searched (MAILSTREAM *stream,long number)
  457. {
  458. }
  459.  
  460.  
  461. void mm_exists (MAILSTREAM *stream,long number)
  462. {
  463. }
  464.  
  465.  
  466. void mm_expunged (MAILSTREAM *stream,long number)
  467. {
  468. }
  469.  
  470.  
  471. void mm_notify (MAILSTREAM *stream,char *string,long errflg)
  472. {
  473.   mm_log (string,errflg);
  474. }
  475.  
  476.  
  477. void mm_mailbox (char *string)
  478. {
  479.   putchar (' ');
  480.   puts (string);
  481. }
  482.  
  483.  
  484. void mm_bboard (char *string)
  485. {
  486.   putchar (' ');
  487.   puts (string);
  488. }
  489.  
  490. void mm_log (char *string,long errflg)
  491. {
  492.   switch ((short) errflg) {
  493.   case NIL:
  494.     printf ("[%s]\n",string);
  495.     break;
  496.   case PARSE:
  497.   case WARN:
  498.     printf ("%%%s\n",string);
  499.     break;
  500.   case ERROR:
  501.     printf ("?%s\n",string);
  502.     break;
  503.   }
  504. }
  505.  
  506.  
  507. void mm_dlog (char *string)
  508. {
  509.   puts (string);
  510. }
  511.  
  512.  
  513. void mm_login (char *host,char *user,char *pwd,long trial)
  514. {
  515.   char tmp[MAILTMPLEN];
  516.   if (curhst) fs_give ((void **) &curhst);
  517.   curhst = (char *) fs_get (1+strlen (host));
  518.   strcpy (curhst,host);
  519.   sprintf (tmp,"{%s} username: ",host);
  520.   prompt (tmp,user);
  521.   if (curusr) fs_give ((void **) &curusr);
  522.   curusr = (char *) fs_get (1+strlen (user));
  523.   strcpy (curusr,user);
  524.   prompt ("password: ",pwd);
  525. }
  526.  
  527.  
  528. void mm_critical (MAILSTREAM *stream)
  529. {
  530. }
  531.  
  532.  
  533. void mm_nocritical (MAILSTREAM *stream)
  534. {
  535. }
  536.  
  537.  
  538. long mm_diskerror (MAILSTREAM *stream,long errcode,long serious)
  539. {
  540. #if unix
  541.   kill (getpid (),SIGSTOP);
  542. #else
  543.   abort ();
  544. #endif
  545.   return NIL;
  546. }
  547.  
  548.  
  549. void mm_fatal (char *string)
  550. {
  551.   printf ("?%s\n",string);
  552. }
  553.  
  554. /* SMTP tester */
  555.  
  556. void smtptest (long debug)
  557. {
  558.   SMTPSTREAM *stream = NIL;
  559.   char line[MAILTMPLEN];
  560.   unsigned char *text = (unsigned char *) fs_get (8*MAILTMPLEN);
  561.   ENVELOPE *msg = mail_newenvelope ();
  562.   BODY *body = mail_newbody ();
  563.   sprintf (line,"%s <%s@%s>",personalname,curusr,curhst);
  564.   rfc822_parse_adrlist (&msg->from,line,curhst);
  565.   sprintf (line,"%s@%s",curusr,curhst);
  566.   rfc822_parse_adrlist (&msg->return_path,line,curhst);
  567.   prompt ("To: ",line);
  568.   rfc822_parse_adrlist (&msg->to,line,curhst);
  569.   if (msg->to) {
  570.     prompt ("cc: ",line);
  571.     rfc822_parse_adrlist (&msg->cc,line,curhst);
  572.   }
  573.   else {
  574.     prompt ("Newsgroups: ",line);
  575.     if (*line) msg->newsgroups = cpystr (line);
  576.     else {
  577.       mail_free_body (&body);
  578.       mail_free_envelope (&msg);
  579.       fs_give ((void **) &text);
  580.     }
  581.   }
  582.   prompt ("Subject: ",line);
  583.   msg->subject = cpystr (line);
  584.   puts (" Msg (end with a line with only a '.'):");
  585.   body->type = TYPETEXT;
  586.   *text = '\0';
  587.   while (gets (line)) {
  588.     if (line[0] == '.') {
  589.       if (line[1] == '\0') break;
  590.       else strcat ((char *) text,".");
  591.     }
  592.     strcat ((char *) text,line);
  593.     strcat ((char *) text,"\015\012");
  594.   }
  595.   body->contents.text = text;
  596.   rfc822_date (line);
  597.   msg->date = (char *) fs_get (1+strlen (line));
  598.   strcpy (msg->date,line);
  599.   if (msg->to) {
  600.     puts ("Sending...");
  601.     if (stream = smtp_open (hostlist,debug)) {
  602.       if (smtp_mail (stream,"MAIL",msg,body)) puts ("[Ok]");
  603.       else printf ("[Failed - %s]\n",stream->reply);
  604.     }
  605.   }
  606.   else {
  607.     puts ("Posting...");
  608.     if (stream = nntp_open (newslist,debug)) {
  609.       if (nntp_mail (stream,msg,body)) puts ("[Ok]");
  610.       else printf ("[Failed - %s]\n",stream->reply);
  611.     }
  612.   }
  613.   if (stream) smtp_close (stream);
  614.   else puts ("[Can't open connection to any server]");
  615.   mail_free_envelope (&msg);
  616.   mail_free_body (&body);
  617. }
  618.